package com.th.supcom.pds.impl.service.adapter;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.carefx.fc.framework.web.gwt.util.FcUtils;
import net.carefx.framework.exception.BusinessException;
import net.carefx.framework.util.ConvertUtils;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.cxf.common.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.th.supcom.bms.domain.dto.ExternalOrdersChargeDTO;
import com.th.supcom.bms.domain.dto.PrescSearchDTO;
import com.th.supcom.bms.domain.vo.ChargeItem;
import com.th.supcom.bms.domain.vo.InPatientInfo;
import com.th.supcom.external.common.api.PrepaymentExternalService;
import com.th.supcom.external.emr.api.OutpOrdersChargeService;
import com.th.supcom.external.presccharge.api.InpPrescChargeService;
import com.th.supcom.external.presccharge.api.OutpPrescChargeService;
import com.th.supcom.external.presccharge.api.OutpPrescRefundService;
import com.th.supcom.pds.domain.pojo.InpPhamApplyDetail;
import com.th.supcom.pds.domain.pojo.InpPhamApplyPatInfo;
import com.th.supcom.pds.domain.vo.InpPhamDispenseDetailVO;
import com.th.supcom.pds.domain.vo.PdsSupplyDetailVO;
import com.th.supcom.pds.domain.vo.PdsSupplyResultSet;
import com.th.supcom.pds.domain.vo.PdsSupplyVO;
import com.th.supcom.pds.domain.vo.PrescSearchDTOVO;
import com.th.supcom.pds.impl.common.PdsConstants;
import com.th.supcom.pds.impl.common.utils.ExceptionThrowHelper;
import com.th.supcom.pds.impl.service.internal.phamapply.InpPhamPatInfoConvertUtils;
import com.th.supcom.pds.medicare.api.AdapterBMSChargeService;

public class AdapterBMSChargeServiceImpl implements AdapterBMSChargeService
{
    /** 日志记录器. */
    public static final Logger s_logger = LoggerFactory.getLogger (AdapterBMSChargeServiceImpl.class);
    private OutpPrescChargeService m_outpPrescChargeService;
    private InpPrescChargeService m_inpPrescChargeService;
    private PrepaymentExternalService m_prepaymentExternalService;
    private OutpPrescRefundService m_outpPrescRefundService;
    private OutpOrdersChargeService m_outpOrdersChargeService;

    public void setOutpOrdersChargeService (OutpOrdersChargeService outpOrdersChargeService)
    {

        m_outpOrdersChargeService = outpOrdersChargeService;
    }

    public void setOutpPrescRefundService (OutpPrescRefundService outpPrescRefundService)
    {
        m_outpPrescRefundService = outpPrescRefundService;
    }

    public void setPrepaymentExternalService (PrepaymentExternalService prepaymentExternalService)
    {
        m_prepaymentExternalService = prepaymentExternalService;
    }

    public void setOutpPrescChargeService (OutpPrescChargeService outpPrescChargeService)
    {
        m_outpPrescChargeService = outpPrescChargeService;
    }

    public void setInpPrescChargeService (InpPrescChargeService inpPrescChargeService)
    {
        m_inpPrescChargeService = inpPrescChargeService;
    }

    @Override
    public String prescriptionCharge (Map <String, Object> params, List <Map <String, Object>> prescChargeItems)
    {
        s_logger.info ("调用处方收费接口prescriptionCharge，参数cardNo:{},prescNoList{}", new Object[]
        { params, prescChargeItems });
        List <ChargeItem> list = new ArrayList <ChargeItem> ();
        String rekNo;
        try
        {
            for (Map <String, Object> map : prescChargeItems)
            {
                ChargeItem chargeItem = new ChargeItem ();
                BeanUtils.populate (chargeItem, map);
                list.add (chargeItem);
            }
            ExternalOrdersChargeDTO externalOrdersChargeDTO = new ExternalOrdersChargeDTO ();
            externalOrdersChargeDTO.setOperator ((String) params.get ("operator"));
            externalOrdersChargeDTO.setTrackData ((String) params.get ("trackData"));
            externalOrdersChargeDTO.setPatientId ((String) params.get ("patientId"));
            externalOrdersChargeDTO.setVisitId ((Long) params.get ("visitId"));
            externalOrdersChargeDTO.setOrdersChargeItems (list);
            rekNo = m_outpOrdersChargeService.outpOrdersCharge (externalOrdersChargeDTO);
        }
        catch (Exception e)
        {
            s_logger.error ("处方收费异常,参数cardNo:{},prescNoList{}", new Object[]
            { params, prescChargeItems, e });
            throw new BusinessException ("处方收费异常" + PdsConstants.DEFALUT_HTML_WRAP + e.getLocalizedMessage (), e);
        }
        return rekNo;
    }

    @Override
    public void prescriptionAccount (List <String> prescNoList)
    {
        s_logger.info ("调用处方记账接口prescriptionCharge,参数prescNoList:{}", prescNoList);
        try
        {
           m_outpPrescChargeService.outpPrescAccount (prescNoList);
        }
        catch (Exception e)
        {
            s_logger.error ("处方记账异常,参数：prescNoList:{}", new Object[]
            { prescNoList, e });
            throw new BusinessException ("处方记账异常" + PdsConstants.DEFALUT_HTML_WRAP + e.getLocalizedMessage (), e);
        }
    }

    @Override
    public List <InpPhamApplyDetail> findChargeItemByExample (PrescSearchDTOVO prescSearchDTOVO)
    {
        s_logger.debug ("调用计费接口查询查询退药药品：patientId:{}" + new Object[]
        { prescSearchDTOVO.getPatientId () });
        PrescSearchDTO prescSearchDTO = ConvertUtils.convert (PrescSearchDTO.class, prescSearchDTOVO);
        prescSearchDTO.setCurrentNursingUnit (prescSearchDTOVO.getNurseUnit ());
        List <ChargeItem> chargeItemsItems;
        try
        {
            chargeItemsItems = m_inpPrescChargeService.findCanRefundPrescription (prescSearchDTO);
        }
        catch (BusinessException e)
        {
            s_logger.error ("查询费用明细出现异常！patientId:{}" + new Object[]
            { prescSearchDTOVO.getPatientId (), e });
            throw new BusinessException ("查询费用明细出现异常！", e);
        }
        if (chargeItemsItems == null || chargeItemsItems.isEmpty ())
        {
            throw new BusinessException ("没有查询到相应的费用明细！");
        }
        List <InpPhamApplyDetail> inpPhamApplyDetails = new ArrayList <InpPhamApplyDetail> ();
        for (ChargeItem chargeItem : chargeItemsItems)
        {
            InpPhamApplyDetail inpPhamApplyDetail = new InpPhamApplyDetail ();
            inpPhamApplyDetail.setPaiVisitId (chargeItem.getPaiVisitId ());
            inpPhamApplyDetail.setChargeDate (chargeItem.getChargeDate ());
            inpPhamApplyDetail.setWard (chargeItem.getOrderByDeptCode ());
            inpPhamApplyDetail.setApplyDispensary (chargeItem.getPerformedByDeptCode ());
            inpPhamApplyDetail.setPhamStdCode (chargeItem.getItemCode ());
            inpPhamApplyDetail.setPhamName (chargeItem.getItemName ());
            inpPhamApplyDetail.setPhamSpec (chargeItem.getSpec ());
            inpPhamApplyDetail.setApplyUnitName (chargeItem.getUnitName ());
            inpPhamApplyDetail.setFactor (chargeItem.getFactor ().intValue ());
            inpPhamApplyDetail.setPhamUnitName (chargeItem.getUnitName ());
            inpPhamApplyDetail.setApplyAmount (chargeItem.getAmount ().intValue ());
            inpPhamApplyDetail.setCosts (chargeItem.getCosts ());
            inpPhamApplyDetail.setCharges (chargeItem.getCharges ());
            inpPhamApplyDetail.setWithdrawApplyNo (chargeItem.getApplyId ());
            inpPhamApplyDetails.add (inpPhamApplyDetail);
        }
        return inpPhamApplyDetails;
    }

    @Override
    public List <InpPhamDispenseDetailVO> phamApplyCharge (List <InpPhamDispenseDetailVO> detailList)
    {
        s_logger.debug ("调用计费接口查询查询退药药品：detailList:{}" + new Object[]
        { detailList });
        List <ChargeItem> chargeList = new ArrayList <ChargeItem> ();
        for (InpPhamDispenseDetailVO inpPhamDispenseDetailVO : detailList)
        {
            ChargeItem item = new ChargeItem ();
            item.setItemCode (inpPhamDispenseDetailVO.getPhamStdCode ());
            item.setItemName (inpPhamDispenseDetailVO.getPhamName ());
            item.setSpec (inpPhamDispenseDetailVO.getPhamSpec ());
            item.setAmount (Double.parseDouble ("" + inpPhamDispenseDetailVO.getApplyAmount ()));
            item.setPaiVisitId (inpPhamDispenseDetailVO.getPaiVisitId ());
            item.setPatientId (inpPhamDispenseDetailVO.getPatientId ());
            item.setVisitId (inpPhamDispenseDetailVO.getVisitCount ());
            item.setUnit (inpPhamDispenseDetailVO.getDispenseUnitName ());
            item.setPrice (inpPhamDispenseDetailVO.getDispensePrice ());
            item.setCosts (inpPhamDispenseDetailVO.getCosts ());
            item.setCharges (inpPhamDispenseDetailVO.getCharges ());
            item.setApplyId (inpPhamDispenseDetailVO.getInpPhamApplyDetailId () + "");
            item.setOrderByDeptCode (inpPhamDispenseDetailVO.getWard ());
            item.setCurrentNursingUnit (inpPhamDispenseDetailVO.getNurseUnit ());
            item.setPerformedByDeptCode (inpPhamDispenseDetailVO.getPerformDispensary ());
            item.setServiceLogOrg (inpPhamDispenseDetailVO.getNurseUnit ());
            item.setInsuranceType (inpPhamDispenseDetailVO.getChargeType ());
            item.setChargeDate (FcUtils.getCurrentServerDateTimeForServer ());
            item.setEnterDate (inpPhamDispenseDetailVO.getOrderEnterDate ());
            item.setOperator (inpPhamDispenseDetailVO.getDispenseBy ());
            item.setOrderId (inpPhamDispenseDetailVO.getOrderId ());
            item.setFactor (1l);
            item.setEnterDate (FcUtils.getCurrentServerDateTimeForServer ());
            item.setUnitName (inpPhamDispenseDetailVO.getDispenseUnitName ());
            item.setApplyClass (inpPhamDispenseDetailVO.getApplyClass ());
            item.setInClassOnRcptCode (inpPhamDispenseDetailVO.getClassOnRcptCode ());
            item.setItemClass (inpPhamDispenseDetailVO.getItemClass ());
            chargeList.add (item);
        }
        try
        {
            chargeList = m_inpPrescChargeService.putPrescription (chargeList);
        }
        catch (Exception e)
        {
            s_logger.error ("调用住院摆药记账接口异常:" + e.getLocalizedMessage (), e);
            throw new BusinessException ("调用住院摆药记账接口异常:" + e.getLocalizedMessage (), e);
        }
        Map <Long, InpPhamDispenseDetailVO> map = new HashMap <Long, InpPhamDispenseDetailVO> ();
        for (InpPhamDispenseDetailVO inpPhamDispenseDetailVO : detailList)
        {
            map.put (inpPhamDispenseDetailVO.getInpPhamApplyDetailId (), inpPhamDispenseDetailVO);
        }
        for (ChargeItem chargeItem : chargeList)
        {
            InpPhamDispenseDetailVO dispenseVO = map.get (Long.parseLong (chargeItem.getApplyId ()));
            dispenseVO.setRekNo (chargeItem.getBillItemId ());
        }
        return detailList;
    }

    @Override
    public List <PdsSupplyResultSet> findOutpReturnChargeItem (Map <String, Object> map)
    {
        s_logger.debug ("调用门诊费用接口查询退药药品信息！参数：patientId:{},prescNo:{}" + new Object[]
        { map.get ("patientId"), map.get ("prescNo") });
        PrescSearchDTO prescSearchDTO = new PrescSearchDTO ();
        List <PdsSupplyResultSet> pdsSupplyResultSets = new ArrayList <PdsSupplyResultSet> ();
        prescSearchDTO.setPatientId ((String) map.get ("patientId"));
        prescSearchDTO.setRecipeNo ((String) map.get ("prescNo"));
        prescSearchDTO.setStartDate ((Date) map.get ("beginDate"));
        prescSearchDTO.setEndDate ((Date) map.get ("endDate"));
        Map <String, List <ChargeItem>> resultMap = new HashMap <String, List <ChargeItem>> ();
        try
        {
            resultMap = m_outpPrescChargeService.findCanRefundPrescriptionForOut (prescSearchDTO);
        }
        catch (BusinessException e)
        {
            s_logger.error (e.getLocalizedMessage (), e);
            throw new BusinessException (e.getMessage (), e);
        }
        catch (final Exception e)
        {
            s_logger.error ("调用门诊药品退药查询接口异常,参数：patientId:{},prescNo:{}" + new Object[]
            { map.get ("patientId"), map.get ("prescNo") });
            throw new BusinessException ("掉用查询退药信息接口失败!", e);
        }
        for (Entry <String, List <ChargeItem>> entry : resultMap.entrySet ())
        {
            PdsSupplyResultSet pdsSupplyResultSet = new PdsSupplyResultSet ();
            pdsSupplyResultSet.setPdsSupplyVO (createPdsSupply (entry));
            pdsSupplyResultSet.setPdsSupplyDetailVOs (createPdsSupplyDetailList (entry));
            pdsSupplyResultSets.add (pdsSupplyResultSet);
        }
        return pdsSupplyResultSets;
    }

    @Override
    public Boolean OutDrugReturnApply (List <PdsSupplyDetailVO> pdsSupplyDetailVOs)
    {
        s_logger.debug ("调用计费接口进行退费申请！入参:pdsSupplyDetailVOs{}", new Object[]
        { pdsSupplyDetailVOs });
        List <ChargeItem> chargeItems = new ArrayList <ChargeItem> ();
        for (PdsSupplyDetailVO pdsSupplyDetailVO : pdsSupplyDetailVOs)
        {
            ChargeItem chargeItem = new ChargeItem ();
            chargeItem.setExternalId (pdsSupplyDetailVO.getOldSupplyDetailId ());
            chargeItem.setAmount (pdsSupplyDetailVO.getUnitQty ());
            chargeItems.add (chargeItem);
        }
        Boolean ApplyResult = null;
        try
        {
            ApplyResult = m_outpPrescRefundService.addRefundApply (chargeItems);
        }
        catch (BusinessException e)
        {
            s_logger.error ("调用计费接口进行退费申请发生异常！入参:pdsSupplyDetailVOs{}", new Object[]
            { pdsSupplyDetailVOs });
            throw new BusinessException (e.getMessage (), e);
        }
        catch (final Exception e)
        {
            s_logger.error (e.getLocalizedMessage (), e);
            throw new BusinessException ("调用计费接口进行退费申请接口失败!", e);
        }
        return ApplyResult;
    }

    /**
     * 提取退药明细信息
     * 
     * @param entry
     * @return
     */
    private List <PdsSupplyDetailVO> createPdsSupplyDetailList (Entry <String, List <ChargeItem>> entry)
    {
        List <PdsSupplyDetailVO> pdsSupplyDetailVOs = new ArrayList <PdsSupplyDetailVO> ();
        List <ChargeItem> chargeItems = entry.getValue ();
        for (ChargeItem chargeItem : chargeItems)
        {
            PdsSupplyDetailVO pdsSupplyDetailVO = new PdsSupplyDetailVO ();
            pdsSupplyDetailVO.setPrescNo (chargeItem.getApplyId ());
            pdsSupplyDetailVO.setOldSupplyDetailId (chargeItem.getExternalId ());
            pdsSupplyDetailVO.setUnitQty (chargeItem.getAmount ());
            pdsSupplyDetailVOs.add (pdsSupplyDetailVO);
        }
        return pdsSupplyDetailVOs;
    }

    /**
     * 生成PdsSupply
     * 
     * @param entry
     * @return
     */
    private PdsSupplyVO createPdsSupply (Entry <String, List <ChargeItem>> entry)
    {
        PdsSupplyVO pdsSupplyVO = new PdsSupplyVO ();
        ChargeItem chargeItem = entry.getValue ().get (0);
        pdsSupplyVO.setPrescNo (entry.getKey ());
        pdsSupplyVO.setPatientId (chargeItem.getPatientId ());
        pdsSupplyVO.setVisitId (chargeItem.getVisitId ());
        return pdsSupplyVO;
    }

    @Override
    public List <InpPhamApplyPatInfo> obtainPatAvailablePrepayment (List <InpPhamApplyPatInfo> patInfoList)
    {
        s_logger.debug ("调用obtainPatAvailablePrepayment方法，参数：patInfoList:{}" + new Object[]
        { patInfoList });
        ExceptionThrowHelper.throwIllegalArgumentException (CollectionUtils.isEmpty (patInfoList), "查询患者预交金时,患者列表为空！");
        List <InPatientInfo> inPatientInfos = new ArrayList <InPatientInfo> ();
        for (InpPhamApplyPatInfo inpPhamApplyPatInfo : patInfoList)
        {
            InPatientInfo inPatientInfo = new InPatientInfo ();
            inPatientInfo.setPatientId (inpPhamApplyPatInfo.getPatientId ());
            inPatientInfo.setPaiVisitId (inpPhamApplyPatInfo.getPaiVisitId ());
            inPatientInfos.add (inPatientInfo);
        }
        try
        {
            inPatientInfos = m_prepaymentExternalService.findPrepaymentByPatientInfos (inPatientInfos);
        }
        catch (Exception e)
        {
            s_logger.error ("查询患者预交金出现异常！");
            throw new BusinessException ("查询预交金出现异常！" + e.getMessage (), e);
        }
        // 将患者信息按患者流水号转话为MAP
        Map <Long, InpPhamApplyPatInfo> map = InpPhamPatInfoConvertUtils.convertListToMapByPatVisitId (patInfoList);
        for (InPatientInfo inPatientInfo : inPatientInfos)
        {
            InpPhamApplyPatInfo inpPatInfo = map.get (inPatientInfo.getPaiVisitId ());
            if (null != inpPatInfo)
            {
                inpPatInfo.setAvailablePrepayment (inPatientInfo.getAvailableAmount ());
            }
        }
        return patInfoList;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.th.supcom.pds.medicare.api.AdapterBMSChargeService#inpPhamRefund(
     * java.util.List) 必填项：m_id（计价项目主键编号） m_itemClass m_itemCode m_itemName
     * m_spec m_amount m_paiVisitId m_visitId m_patientId m_unit m_price m_costs
     * m_charges m_applyId m_orderByDeptCode m_performedByDeptCode
     * m_serviceLogOrg m_insuranceType m_chargeDate m_enterDate m_subjCode
     * m_classOnRcptCode m_applyClass m_operator m_orderId
     * 
     * @return 已记账的药品信息列表
     * 
     * @throws BusinessException 抛出业务异常
     */
    @Override
    public Boolean inpPhamRefund (List <InpPhamDispenseDetailVO> detailList)
    {
        s_logger.debug ("调用inpPhamRefund方法，参数：detailList:{}", new Object[]
        { detailList });
        try
        {
            List <ChargeItem> chargeItems = convertPdsReturnInfoToBms (detailList);
            return m_inpPrescChargeService.refundPrescription (chargeItems);
        }
        catch (Exception e)
        {
            s_logger.error ("退费时出现异常！参数：detailList:{}", new Object[]
            { detailList });
            throw new BusinessException ("退费时出现异常！" + e.getMessage (), e);
        }
    }

    private List <ChargeItem> convertPdsReturnInfoToBms (List <InpPhamDispenseDetailVO> detailList)
    {
        List <ChargeItem> chargeItems = new ArrayList <ChargeItem> ();
        for (InpPhamDispenseDetailVO inDetailVO : detailList)
        {
            ChargeItem item = new ChargeItem ();
            item.setItemCode (inDetailVO.getPhamStdCode ());
            item.setAmount (Double.parseDouble ("" + -inDetailVO.getApplyAmount ()));
            item.setPaiVisitId (inDetailVO.getPaiVisitId ());
            item.setApplyId (inDetailVO.getWithdrawApplyNo () + "");
            item.setOperator (inDetailVO.getDispenseBy ());
            chargeItems.add (item);
        }
        return chargeItems;
    }

    /** 公司版权信息. */
    public static final String copyright = "Copyright 2014, XuNuo Corporation";

    /** 提交路径. */
    public static final String SCC_BRANCH = "$URL$";

    /** 提交日期. */
    public static final String SCC_LAST_MODIFICATION_DATE = "$Date$";

    /** 最终修改人员. */
    public static final String SCC_LAST_MODIFIER_NAME = "$Author$";

    /** 最终版本号. */
    public static final String SCC_REVISION = "$Revision$";

}
